#include <memory/spw_sha_ptr.h>
#include <gtest/gtest.h>
#include <memory/spw_alloc.h>
#include <memory/spw_uni_ptr.h>
using namespace spwstd;
using namespace spwexcept;
using namespace spwstd::spwptr;
// bad_weak_ptr测试
TEST(ExpectTest, BadweakptrTest){
    EXPECT_THROW(throw BadWeakPtr(), BadWeakPtr);
    EXPECT_STREQ(BadWeakPtr().What(), "spwstd::spwexcept::BadWeakPtr" );
}

// 控制块测试
static int testflag = 111;
static int deltest = 111;

class CountBaseTest: public testing::Test
{
protected:
    virtual void SetUp() override {
        std::cout << "-----------"<< __func__ << " setup-----------" << std::endl; 
    }
    virtual void TearDown() override {
        std::cout << "-----------" << __func__ << " teardown-----------" << std::endl; 
    }

public:

struct TestClass{
    TestClass(int a, double b):a_(a), b_(b){ testflag = 1; }
    int a_;
    double b_;
    ~TestClass() { testflag = 0; }
};
struct DerivedClass: TestClass{
    DerivedClass(int a, double b):TestClass{a,b}{}
};
// AllocTest, DelTest
struct DelTest{
    void operator()(TestClass* t){
        deltest = 1;
        delete t;
    }
} del;

};

TEST_F(CountBaseTest, CountPtrTest){
    CountPtr<TestClass*>* p1{new CountPtr<TestClass*>(new TestClass{1,1.0}) };

    EXPECT_TRUE(p1->GetCounts() == 1);
    EXPECT_TRUE(p1->GetDeleter(typeid(nullptr)) == nullptr);

    // sharecount 被复制，引用计数+1
    p1->AddRefCopy();
    EXPECT_TRUE(p1->GetCounts() == 2);

    // weakptr被构造
    p1->WeakAddRefCopy(); 

    // 当sharecount析构, use_count - 1
    p1->Release();
    // 现在还有一个shareptr引用，和2个weakptr
    EXPECT_TRUE(p1->GetCounts() == 1);
    // --use_count == 0, 调用dispose(), 所指对象被析构; weak_count-1 == 1, 还剩一个weakptr
    p1->Release();
    // 所指对象已经析构，testflag==0
    EXPECT_TRUE(testflag == 0);
    p1->WeakRelease();
    // 控制块析构
}

TEST_F(CountBaseTest, DelAllocTest){
    using DelAlloc = DelAllocCount<TestClass*, DelTest, DefaultAlloc<void>>;
    DelAlloc* p2 {new DelAlloc{new TestClass{2,2.0}, del, DefaultAlloc<void>()}};

    using DelAlloc2 = DelAllocCount<TestClass*, DelTest, PoolAlloc<void>>;
    DelAlloc2* p3 {new DelAlloc2{new TestClass{2,2.0}, del, PoolAlloc<void>()}};
    {
    // alloc = DefaultAlloc
    testing::StaticAssertTypeEq< 
        DelAllocCount<TestClass*, DelTest, DefaultAlloc<void>>::AllocType,
        DefaultAlloc<DelAllocCount<TestClass*, DelTest, DefaultAlloc<void>>> >();

    EXPECT_TRUE(sizeof(*p2) == 24);
    TestClass* t = new TestClass{1,1.0};
    EXPECT_TRUE(testflag == 1);
    (*reinterpret_cast<DelTest*>(p2->GetDeleter(typeid(DelTest))))(t);
    EXPECT_TRUE(deltest == 1);
    deltest = 0;
    EXPECT_TRUE(testflag == 0);
    // weak_count=1, use_count=2
    p2->AddRefCopy();
    EXPECT_TRUE(p2->GetCounts() == 2);
    // weak_count=2, use_count=2; 创造一个weakptr
    p2->WeakAddRefCopy();
    // use_count=1, weak_count=2;
    p2->Release();
    EXPECT_TRUE(p2->GetCounts() == 1);
    // use_count=0, weak_count=1所指对象被析构内存被释放，但控制块没有析构
    p2->Release();
    EXPECT_TRUE(testflag == 0);
    EXPECT_TRUE(deltest == 1);
    deltest = 0;
    // ~DefaultAlloc()被调用, p2所指内存块析构
    p2->WeakRelease();
    }
    {
    // PoolAlloc
    testing::StaticAssertTypeEq< 
        DelAllocCount<TestClass*, DelTest, PoolAlloc<void>>::AllocType,
        PoolAlloc<DelAllocCount<TestClass*, DelTest, PoolAlloc<void>>> >();
    // weak_count=1, use_count=2
    p3->AddRefCopy();
    EXPECT_TRUE(p3->GetCounts() == 2);
    // weak_count=2, use_count=2; 创造一个weakptr
    p3->WeakAddRefCopy();
    // use_count=1, weak_count=2;
    p3->Release();
    EXPECT_TRUE(p3->GetCounts() == 1);
    // use_count=0, weak_count=1所指对象被析构内存被释放，但控制块没有析构
    p3->Release();
    EXPECT_TRUE(testflag == 0);
    EXPECT_TRUE(deltest == 1);
    deltest = 0;
    // ~DefaultAlloc()被调用, p2所指内存块析构
    p3->WeakRelease();
    }
}

TEST_F(CountBaseTest, MakeSharedCountTest){
    using MakeSharedAlloc = MakeSharedCount<TestClass, DefaultAlloc<void>>;

    MakeSharedAlloc* p4 = new MakeSharedAlloc( DefaultAlloc<void>(), 3, 3.0);
    testing::StaticAssertTypeEq<MakeSharedCount<TestClass,DefaultAlloc<void>>::AllocType,
        DefaultAlloc<MakeSharedAlloc>>();

    EXPECT_TRUE(sizeof(*p4)==(4+4+sizeof(TestClass)+8));
    // getDeleter返回所指对象地址
    EXPECT_TRUE(static_cast<TestClass*>(p4->GetDeleter(typeid(MakeSharedTag)))->a_ == 3);
    EXPECT_TRUE(static_cast<TestClass*>(p4->GetDeleter(typeid(MakeSharedTag)))->b_ == 3.0);
    EXPECT_TRUE(testflag == 1);

    // weak_count=1, use_count=2
    p4->AddRefCopy();
    EXPECT_TRUE(p4->GetCounts() == 2);
    // weak_count=2, use_count=2; 创造一个weakptr
    p4->WeakAddRefCopy();
    // use_count=1, weak_count=2;
    p4->Release();
    EXPECT_TRUE(p4->GetCounts() == 1);
    // use_count=0, weak_count=1所指对象被析构内存被释放，但控制块没有析构
    p4->Release();
    EXPECT_TRUE(testflag == 0);
    // ~DefaultAlloc()被调用, p2所指内存块析构
    p4->WeakRelease();
}

// 控制块测试
TEST_F(CountBaseTest, ShareCountTest) {
    // 构造函数
    auto a1 = ShareCount();
    EXPECT_TRUE(a1.GetPtr() == nullptr);
    TestClass* t1 = new TestClass{4,4.0};
    ShareCount a2(t1);
    EXPECT_TRUE(a2.GetCounts() == 1);
    TestClass* t2 = new TestClass{5,5.0};
    ShareCount a3(t2, del, DefaultAlloc<void>());
    EXPECT_TRUE(a3.GetCounts() == 1);
    //TestClass* t3 = new TestClass{6,6.0};
    ShareCount a4(MakeSharedTag(),reinterpret_cast<TestClass*>(0), DefaultAlloc<void>(), 6, 6.0);
    EXPECT_TRUE(a4.GetCounts() == 1);

    UniquePtr<TestClass> ut{new TestClass(7,7.0)};
    ShareCount a5(spwuti::move(ut));
    EXPECT_TRUE(a5.GetCounts() == 1);

    ShareCount a6(a5);
    EXPECT_TRUE(a6.GetCounts() == 2);
    a5 = a4;
    EXPECT_TRUE(a4.GetCounts() == 2);
    EXPECT_TRUE(a4 == a5);

    a5.Swap(a4);
    EXPECT_TRUE(a5.GetCounts() == 2);
}

TEST_F(CountBaseTest, WeakCountTest) {
    auto b1 = WeakCount();
    EXPECT_TRUE(b1.GetPtr() == nullptr);

    EXPECT_TRUE(testflag == 0);
    TestClass* t1 = new TestClass{4,4.0};
    EXPECT_TRUE(testflag == 1);
    ShareCount s(t1);
    WeakCount b2(s);
    EXPECT_TRUE(b2.GetPtr()->GetCounts() == 1);
    WeakCount b3(b2);
    EXPECT_TRUE(b3.GetPtr()->GetCounts() == 1);
    WeakCount b4(spwuti::move(b3));
    b3 = s;
    b3 = b4;
    b3 = spwuti::move(b4);
    b4 = b3;
    ShareCount a(b2);
    EXPECT_TRUE(b3 == b4);
}

// 测试shareptr
TEST_F(CountBaseTest, SharePtr) {
    ShareCount a{};
    DerivedClass* p1 = new DerivedClass(1,1.0);
    SharePtr<TestClass> s1(p1);
    EXPECT_TRUE(s1.GetCounts() == 1);

    DerivedClass* p2 = new DerivedClass(2,2.0);
    SharePtr<TestClass> s2(p2,del,DefaultAlloc<void>());
    EXPECT_TRUE(s2.GetCounts() == 1);

    // 只建立一个控制块，所指对象为nullptr待定
    SharePtr<TestClass> s3(nullptr, del);
    EXPECT_TRUE(s3.GetCounts() == 1);
    DerivedClass* p3 = new DerivedClass(3,3.0);
    // 别名构造函数，s4析构时，会delete s3所指对象，和p3无关；但是get()得到是p3复制
    // p3 要和s3所指对象同生命
    SharePtr<TestClass> s4(s3, p3);
    EXPECT_TRUE(s4.GetCounts() == 2);
    EXPECT_TRUE(s4->a_ == 3);
    delete p3;

    SharePtr<TestClass> s5(spwuti::move(s2));
    EXPECT_TRUE(s5.GetCounts() == 1);

    // 只建立一个控制块，所指对象为nullptr待定
    UniquePtr<TestClass> ut{new TestClass(4,4.0)};
    SharePtr<TestClass> s6(spwuti::move(ut));
    EXPECT_TRUE(s6.GetCounts() == 1);
    EXPECT_TRUE(s6->a_ == 4);

    // operator =
    s6 = s5;
    EXPECT_TRUE(s6.GetCounts() == 2);
    EXPECT_TRUE(s6->a_ == 2);
    s6 = spwuti::move(s5);
    EXPECT_TRUE(s6.GetCounts() == 1);
    EXPECT_TRUE(s6->a_ == 2);
    UniquePtr<TestClass> ut2{new TestClass(5,5.0)};
    EXPECT_TRUE(testflag == 1);
    // 因为原来s6所指对象析构，所以testflag=0
    s6 = spwuti::move(ut2);
    EXPECT_TRUE(testflag == 0);
    EXPECT_TRUE(s6.GetCounts() == 1);
    EXPECT_TRUE(s6->a_ == 5);

    s6.Reset();
    EXPECT_TRUE(testflag == 0);
    EXPECT_TRUE(s6.Get() == nullptr);

    TestClass* t6{new TestClass(6,6.0)}; 
    s6.Reset(t6);
    EXPECT_TRUE(s6.GetCounts() == 1);
    EXPECT_TRUE(s6->a_ == 6);
    EXPECT_TRUE((*s6).a_ == 6);
    
    EXPECT_TRUE(s6);
    EXPECT_TRUE(s6.IsUnique());
}

// 测试weakptr
TEST_F(CountBaseTest, WeakPtr) {
    WeakPtr<TestClass> w;
    DerivedClass* t1 = new DerivedClass{1,1.0};
    SharePtr<TestClass> s1(t1);
    EXPECT_TRUE(s1.GetCounts() == 1);
    WeakPtr<TestClass> w1(s1);
    EXPECT_TRUE(s1.GetCounts() == 1);
    WeakPtr<TestClass> w2(spwuti::move(w1));
    EXPECT_TRUE(s1.GetCounts() == 1);
    // s1所指对象析构，但weakptr保留了s1控制块，但所指对象为nullptr
    SharePtr<TestClass> s2 = w2.Lock();
    EXPECT_TRUE(s2.GetCounts() == 2);
    EXPECT_TRUE(s1.GetCounts() == 2);

    SharePtr<TestClass> s3(w2);
    EXPECT_TRUE(s3.GetCounts() == 3);
    EXPECT_TRUE(s2.GetCounts() == 3);
    EXPECT_TRUE(s1.GetCounts() == 3);

    s1 = nullptr;
    EXPECT_TRUE(s3.GetCounts() == 2);
    EXPECT_TRUE(s2.GetCounts() == 2);
    s2 = nullptr;
    EXPECT_TRUE(s3.GetCounts() == 1);
    s3 = nullptr;
    EXPECT_TRUE(s1.GetCounts() == 0);
    EXPECT_TRUE(s3.GetCounts() == 0);
    EXPECT_TRUE(s2.GetCounts() == 0);
    EXPECT_TRUE(w2.GetCounts() == 0);

    EXPECT_TRUE(w2.Expired());

    SharePtr<TestClass> s4 = w2.Lock();
    EXPECT_TRUE(s2.Get() == nullptr);

    EXPECT_THROW(
        {
            SharePtr<TestClass> s5(w2);
        }, BadWeakPtr );
    // operator =
    SharePtr<TestClass> s5{new TestClass{5,5.0}};
    SharePtr<DerivedClass> d6{new DerivedClass{6,6.0}};
    SharePtr<TestClass> s6 = d6;

    WeakPtr<TestClass> w3 = d6;
    WeakPtr<DerivedClass> wd = d6;
    w3 = spwuti::move(w2);
    w3 = spwuti::move(d6);
}

// 测试makeshared
TEST_F(CountBaseTest, MakeSharedTest) {
    auto s = makeShared<TestClass>(1,1.0);
    EXPECT_TRUE(s->a_ == 1);
}
